import React, { ChangeEvent, useRef, useState } from "react";
import axios from "axios";
import Button from "../Button/button.tsx";
import UploadList from "./uploadList.tsx";
import Dragger from "./dragger.tsx";

export type UploadFileStatus = "ready" | "uploading" | "success" | "error";
export interface IUploadFile {
    uid: string;
    size: number;
    name: string;
    status?: UploadFileStatus;
    percent?: number;
    raw?: File;
    response?: any;
    err?: any;
}

export interface IUploadProps {
    action: string; // 发送的接口
    defaultFileList?: IUploadFile[];  // 默认列表
    // 各类生命周期
    beforeUpload?: (file: File) => boolean | Promise<File>; // 返回布尔值或者promise处理后的文件
    onProgress?: (percentage: number, file: File) => void;
    onSuccess?: (data: any, file: File) => void;
    onError?: (err: any, file: File) => void;
    onChange?: (file: File) => void;
    onRemove?: (file: IUploadFile) => void;
    // 定制化请求参数
    headers?: { [key: string]: any };
    name?: string;
    data?: { [key: string]: any }; // 额外参数
    withCredentials?: boolean; // 是否携带cookies
    // input本身的file约束属性
    accept?: string;  // 允许的文件类型
    multiple?: boolean; // 多选
    drag?: boolean; // 拖动上传
    children?: any
}
const Upload: React.FC<IUploadProps> = (props) => {
    const { action, defaultFileList, beforeUpload, onProgress, onSuccess, onError, onChange, onRemove,
        headers, name = "file", data, withCredentials, accept, multiple, children, drag } = props;
    const [fileList, setFileList] = useState<IUploadFile[]>(defaultFileList || []);
    const fileInput = useRef<HTMLInputElement>(null);

    // 更新列表内容 updateObj待更新的内容
    const updateFileList = (updateFile: IUploadFile, updateObj: Partial<IUploadFile>) => {
        setFileList((prevList) => {
            return prevList.map(file => {
                if (file.uid === updateFile.uid) {
                    // 判断uid是否一样再更新
                    return { ...file, ...updateObj };
                } else {
                    return file;
                }
            });
        });
    }

    // 处理点击
    const handleClick = () => {
        if (fileInput.current) {
            fileInput.current.click();
        }
    }
    // 文件上传
    const uploadFiles = (files: FileList) => {
        let postFiles = Array.from(files); // 类数组转化为数组
        postFiles.forEach(file => {
            if (!beforeUpload) {
                // 直接上传
                myPost(file);
            } else {
                const result = beforeUpload(file);
                if (result && result instanceof Promise) {
                    result.then(processedFile => {
                        myPost(processedFile);
                    });
                } else if (result !== false) {
                    myPost(file);
                }
            }

        });
    }
    // post方法
    const myPost = (file: File) => {
        let _file: IUploadFile = {
            uid: Date.now() + "upload_file",
            size: file.size,
            name: file.name,
            status: "ready",
            percent: 0,
            raw: file,
        }
        // setFileList([_file, ...fileList]); // 更新文件列表
        setFileList(prevList => {
            return [_file, ...prevList];
        });
        const formData = new FormData();
        formData.append(name || "file", file);
        // 添加更多数据
        if (data) {
            Object.keys(data).forEach(key => {
                formData.append(key, data[key]);
            });
        }
        axios.post(action, formData, {
            headers: {
                // 添加自定义headers
                ...headers,
                // jsonplaceholder.typicode.com/posts 只支持 JSON 数据，不支持 multipart/form-data。
                // 改用 application/json
                "Content-Type": "application/json"
            },
            withCredentials,
            onUploadProgress: (e) => {
                let percentage = Math.round((e.loaded * 100) / (e.total ? e.total : 0)); // 百分比
                if (percentage <= 100) {
                    // 修改文件状态
                    updateFileList(_file, {
                        percent: percentage,
                        status: "uploading"
                    });
                    if (onProgress) {
                        onProgress(percentage, file); // 调用在过程中方法
                    }
                }
            }
        }).then(resp => {
            console.log("成功:", resp);
            updateFileList(_file, {
                status: "success",
                response: resp.data
            });
            if (onSuccess) {
                onSuccess(resp.data, file);
            }
            if (onChange) {
                onChange(file);
            }
        }).catch(err => {
            console.log("失败:", err);
            updateFileList(_file, {
                status: "error",
                response: err
            });
            if (onError) {
                onError(err, file);
            }
            if (onChange) {
                onChange(file);
            }
        });
    }
    // input内容变化时
    const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
        const files = e.target.files;
        if (!files) {
            return;
        }
        uploadFiles(files); // 文件上传方法
        // 清空指向
        if (fileInput.current) {
            fileInput.current.value = '';
        }
    }
    // 移除文件
    const handleRemove = (file: IUploadFile) => {
        // 更新列表
        setFileList((prevList) => {
            return prevList.filter((item) => item.uid !== file.uid);
        });
        if (onRemove) {
            onRemove(file);
        }
    };

    return (
        <div className="upload-component">
            <div className="upload-input" style={{ display: "inline-block" }} onClick={handleClick}>
                {drag ? (
                    <Dragger
                        onFile={(files) => {
                            uploadFiles(files);
                        }}
                    >
                        {children}
                    </Dragger>
                ) : (
                    children
                )}
                <input
                    type="file"
                    className="file-input"
                    data-testid="file-input"
                    title="file"
                    ref={fileInput}
                    style={{ display: "none" }}
                    onChange={handleChange}
                    accept={accept}
                    multiple={multiple}
                />
            </div>
            {/* <Button
                btnType="primary"
                size="sm"
                onClick={handleClick}
            >
                上传文件
            </Button> */}

            <UploadList fileList={fileList} onRemove={handleRemove}></UploadList>
        </div>
    );
}


export default Upload;